<template>
    <div class="knob" ref="knobRef">
        <div class="knob-control" :style="knobStyle" @mousedown.left="startDrag" @touchstart.passive="startDrag"
            @dblclick.prevent="reset" @contextmenu.prevent>
        </div>
        <label v-if="false">{{ label }}</label>
    </div>
</template>

<script>
import { defineComponent, ref, computed, watch, onMounted, onUnmounted } from 'vue';

export default defineComponent({
    name: 'Knob',
    props: {
        label: String,
        minAngle: {
            type: Number,
            default: -150
        },
        maxAngle: {
            type: Number,
            default: 150
        },
        initialValue: {
            type: Number,
            default: 0.5
        },
        knobImage: {
            type: String,
            required: true
        },
        sensitivity: {
            type: Number,
            default: 0.002
        }
    },
    setup(props, { emit }) {
        const value = ref(props.initialValue);
        const isDragging = ref(false);
        const startX = ref(0);
        const knobRef = ref(null);

        const knobStyle = computed(() => {
            // Map value (0-1) to sprite index (0-104)
            const spriteIndex = Math.round(value.value * 104);
            const spriteY = spriteIndex * 120;
            return {
                backgroundImage: `url(${props.knobImage})`,
                backgroundPosition: `0 -${spriteY}px`
            };
        });

        const startDrag = (event) => {
            event.preventDefault();
            isDragging.value = true;
            startX.value = event.type.startsWith('touch') ? event.touches[0].clientX : event.clientX;
            window.addEventListener('mousemove', drag, { passive: false });
            window.addEventListener('touchmove', drag, { passive: false });
            window.addEventListener('mouseup', stopDrag);
            window.addEventListener('touchend', stopDrag);
            window.addEventListener('blur', stopDrag);
        };

        const drag = (event) => {
            if (!isDragging.value) return;
            event.preventDefault();
            const currentX = event.type.startsWith('touch') ? event.touches[0].clientX : event.clientX;
            const deltaX = currentX - startX.value;
            startX.value = currentX;
            const newValue = value.value + deltaX * props.sensitivity;
            value.value = Math.min(1, Math.max(0, newValue));
            emit('input', value.value);
        };

        const stopDrag = () => {
            isDragging.value = false;
            window.removeEventListener('mousemove', drag);
            window.removeEventListener('touchmove', drag);
            window.removeEventListener('mouseup', stopDrag);
            window.removeEventListener('touchend', stopDrag);
            window.removeEventListener('blur', stopDrag);
        };

        const reset = () => {
            value.value = props.initialValue;
            emit('input', value.value);
        };

        watch(value, (newValue) => {
            emit('valueChange', { label: props.label, value: newValue });
        });

        onMounted(() => {
            if (knobRef.value) {
                knobRef.value.addEventListener('touchstart', (e) => e.preventDefault(), { passive: false });
            }
        });

        onUnmounted(() => {
            stopDrag();
            if (knobRef.value) {
                knobRef.value.removeEventListener('touchstart', (e) => e.preventDefault());
            }
        });

        return {
            knobStyle,
            startDrag,
            reset,
            knobRef
        };
    }
});
</script>

<style scoped>
.knob {
    width: 80px;
    height: 80px;
    text-align: center;
    position: absolute;
    top: 64.5%;
    left: 47%;
    user-select: none;
}

.knob-control {
    background-repeat: no-repeat;
    background-size: 120px 12600px;
    /* Size for 105 steps (0-104) */
    width: 120px;
    height: 120px;
    cursor: ew-resize;
    touch-action: none;
}

label {
    display: none;
}
</style>